package com.ajavaer.framework.weixin;

import com.ajavaer.framework.AjavaerCache;
import com.ajavaer.framework.cache.type.CacheEngine;
import com.ajavaer.framework.cache.type.CacheItem;
import com.ajavaer.framework.common.message.Message;
import com.ajavaer.framework.common.tools.HttpTools;
import com.ajavaer.framework.common.tools.JsonTools;
import com.ajavaer.framework.config.WeixinConfig;
import com.ajavaer.framework.config.WeixinJsSDKConfig;
import com.ajavaer.framework.config.WeixinPublicConfig;
import com.ajavaer.framework.handle.CacheHandle;
import com.ajavaer.framework.handle.CaffeineHandle;
import com.ajavaer.framework.message.WeixinJssdkShare;
import com.ajavaer.framework.message.WeixinJssdkTicket;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.util.Formatter;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 微信Jssdk模块
 */
@Component
public class WeixinJsSDK {

    private Logger log = LoggerFactory.getLogger(WeixinJsSDK.class);
    @Resource
    private WeixinJsSDKConfig weixinJsSDKConfig;
    @Resource
    private WeixinPublic weixinPublic;
    @Resource
    private WeixinConfig weixinConfig;
    @Resource
    private WeixinPublicConfig weixinPublicConfig;


    /**
     * 获得jsApiTicket,如果不存在,则从微信服务器获取一个,并缓存起来,缓存有效期7200秒,如果获取失败,则返回错误信息
     *
     * @return
     */
    public Message<String> getJsApiTicket() {
        Message<String> accessToken = weixinPublic.getAccessToken();
        Message<String> result = Message.success("OK");
        if (accessToken.isSuccess()) {
            CacheHandle<String, String> cacheHandle = AjavaerCache.get(weixinConfig.getCacheEngine());
            String ticket = cacheHandle.get(weixinJsSDKConfig.getTicketCacheKey(), key -> {
                String url = weixinJsSDKConfig.getJsapi_ticket_url(accessToken.getData());
                Message<WeixinJssdkTicket> ticketResultMessage = HttpTools.get(url, WeixinJssdkTicket.class);
                log.debug("Get Access Token From Wx,url:{},res:{}", url, JsonTools.beanToJson(ticketResultMessage));
                if (ticketResultMessage.isSuccess()) {
                    WeixinJssdkTicket ticketResult = ticketResultMessage.getData();
                    if (ticketResult.success()) {
                        return CacheItem.of(key, ticketResult.getTicket(), ticketResult.getExpires_in(), TimeUnit.SECONDS);
                    } else {
                        result.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
                        result.setMsg("get JsTicket error:" + ticketResult.getErrmsg());
                        log.error("weixin error:{}", JsonTools.beanToJson(ticketResult));
                    }
                } else {
                    result.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
                    result.setMsg(ticketResultMessage.getMsg());
                    log.error("connect weixin server error:{}", ticketResultMessage.getMsg());
                }
                return null;
            });
            result.setData(ticket);
        } else {
            result.setMsg(accessToken.getMsg());
            result.setCode(accessToken.getCode());
        }
        return result;
    }

    /**
     * 签名计算
     *
     * @param url
     * @return
     */
    public Message<WeixinJssdkShare> sign(String url) {
        Message<String> ticket = getJsApiTicket();
        if (!ticket.isSuccess()) {
            return Message.fail(ticket.getCode(), ticket.getMsg());
        }
        String nonce_str = create_nonce_str();
        String timestamp = create_timestamp();
        String string1;
        String signature = "";
        try {
            url = URLDecoder.decode(url, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage(), e);
        }
        // 注意这里参数名必须全部小写，且必须有序
        string1 = String.format("jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s", ticket.getData(), nonce_str, timestamp, url);
        if (weixinConfig.getDebug()) {
            log.debug(string1);
        }
        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        WeixinJssdkShare share = new WeixinJssdkShare();
        share.setAppid(weixinPublicConfig.getAppid());
        share.setDebug(weixinConfig.getDebug());
        share.setNonceStr(nonce_str);
        share.setTimestamp(timestamp);
        share.setSignature(signature);
        share.setUrl(url);
        return Message.successResult(share);
    }

    private String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

    private String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }

    private String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

}
